Release 10.1A: OpenEdge Development:
Programming Interfaces


Managing Progress session IDs

A Progress session ID can serve a variety of functions, including any one or more of the following:

You can set the Progress session ID from a user ID that is authenticated using an external authentication system. If you do not explicitly set it, the Progress session ID is considered blank. You can also clear an existing Progress session ID, which resets the effective ID to blank.

To set a Progress session ID, you must build a trusted domain registry for the application at run time in order to assert and validate an authenticated user ID as a valid Progress session ID, and optionally as a database connection ID.

Building the application trusted domain registry

You can build an application trusted domain registry from the contents of an existing database trusted domain registry or create individual domain entries directly in your 4GL code. The SECURITY-POLICY system handle provides methods that you can use to build an application trusted domain registry as described in Table 2–5.

Table 2–5: Methods for building an application domain registry
This SECURITY-POLICY method...
Provides this function...
LOAD-DOMAINS( integer-expression | 
              logical-name | alias ) 
Loads the application trusted domain registry with the existing domain entries from the database trusted domain registry of a specified OpenEdge RDBMS. (The integer-expression parameter specifies the database by its order of connection in the Progress session.)
You can only call this method once successfully. A successful call to this method implicitly locks the application trusted domain registry against any further changes.1

Note: This method for loading the application trusted domain registry is more secure than using the REGISTER-DOMAIN( ) and LOCK-REGISTRATION( ) methods.

REGISTER-DOMAIN 
   ( domain-name , 
     access-code 
     [ , domain-description 
         [ , domain-type ] ] ) 
Creates a new domain entry in the application trusted domain registry. The domain-name parameter specifies the required value for the DOMAIN-NAME attribute of the client-principal object in order for that object to validate against the domain entry (see Table 2–3). The access-code parameter specifies the value to use as the key for sealing a client-principal object in order for the object to validate against this domain entry (see Table 2–4).
You can no longer call this method after calling the LOCK-REGISTRATION( ) method.

Note: The domain-description and domain-type values do not have to match the DOMAIN-DESCRIPTION and DOMAIN-TYPE attributes in a client-principal object in order for the object to validate against the domain entry.

LOCK-REGISTRATION( ) 
Locks the application trusted domain registry against any further registrations using the REGISTER-DOMAIN( ) method.1 You must call this method before you can use the application domain registry to validate identities that you have built using the REGISTER-DOMAIN( ) method.
1Once the application trusted domain registry is locked, it cannot be changed during the Progress session. The only way to change it is to restart the session and reload the registry.

The REGISTER-DOMAIN( ) method provides the flexibility to dynamically define a trusted authentication domain not otherwise available in a database domain registry. However, until you call the LOCK-REGISTRATION( ) method, you have risk of a security breach by allowing the possible registration of rogue domains in the application domain registry. The LOAD-DOMAINS( ) method minimizes this risk by providing a secure pathway to load and lock the entire contents of an existing database domain registry (and only the contents of that registry) into the application domain registry.

Setting the Progress session ID

Most 4GL applications authenticate a user ID that is authenticated externally, without any reference to the _User table. This session-wide user ID is then used to authorize application features using the 4GL CAN-DO function (see the "Authorizing access to procedures and database resources" section) or some other application-defined authorization mechanism.

Using a client-principal object and the application trusted domain registry with appropriate database configuration options, you can assert this externally authenticated user ID to OpenEdge as the Progress session ID, which can then recognize it for use with various OpenEdge features. For example:

With a common application user ID, you can set a single Progress session ID maintained using a client-principal object and transport this user identity between Progress sessions of a distributed application to maintain a consistent identity among them (see the "Managing application user IDs in n-tier applications" section).

If you want to set a Progress session ID from a user ID that you authenticate externally, you must have a corresponding domain entry registered in the application trusted domain registry. As described in an earlier section (see the "Building the application trusted domain registry" section), you can build this registry within the Progress session at run time entirely from a configured database trusted domain registry or you can build it one domain entry at a time directly from 4GL code. It is generally easier and more secure to load the application domain registry from the existing database domain registry of an OpenEdge RDBMS.

Any user ID that you authenticate with an external authentication system has no OpenEdge-supported functional identity until you specifically assert and validate that identity against the corresponding authentication domain. This you must do using a client-principal object.

To assert and validate an externally authenticated Progress session ID:

  1. Build the application trusted domain registry using methods of the SECURITY-POLICY system handle.
  2. Input the candidate user ID and authentication criteria (password, for example).
  3. Create and initialize a client-principal object with the user ID and corresponding authentication domain information that is in your application trusted domain registry.
  4. Authenticate the user ID through the external authentication system.
  5. If the authentication succeeds, proceed to Step 6. If the authentication fails, invalidate the client-principal object with the AUTHENTICATION-FAILED( ) method and proceed or exit the procedure accordingly.
  6. Log in the client session and seal the client-principal object using the access code assigned to your authentication domain.
  7. Assert and validate the authenticated user ID represented by the client-principal object as a Progress session ID using the SET-CLIENT( ) method on the SECURITY-POLICY system handle. The SET-CLIENT( ) method always validates the client-principal object against the application trusted domain registry in order to set the Progress session ID.
  8. Note: By default, if any connected databases do not currently have database connection IDs, the SET-CLIENT( ) method also attempts to validate and set the database connection ID for each of these databases using the trusted domain registry configured for each database. This setting can always be overridden using the 4GL SETUSERID or SET-DB-CLIENT functions. However, if database options are set to trust the application domain registry, both SET-CLIENT( ) and SET-DB-CLIENT use the application trusted domain registry to validate and set the database connection ID for that database.

    Note: If the application trusted domain registry is not initialized and remains unlocked, SET-CLIENT( ) does not validate a Progress session ID, but does propagate the client-principal object validate and set database connection IDs, according to database connection status and configuration.

  9. Manage the rest of the client login session as usual (see the "Managing client login sessions" section).

Thus, you might use a code fragment such as the following, which sets up an externally authenticated client login session in order to set a Progress session ID for an inventory application that accesses a single database (already connected). The bold-faced code features the client login session management and authentication elements:

Login session for an externally authenticated Progress session ID
DEFINE VARIABLE hCP AS HANDLE NO-UNDO. 
DEFINE VARIABLE hAuthProc AS HANDLE NO-UNDO. 
DEFINE VARIABLE cUserID AS CHARACTER NO-UNDO. 
DEFINE VARIABLE cPassword AS CHARACTER NO-UNDO. 
DEFINE VARIABLE cAccessCode AS CHARACTER NO-UNDO. 
/* Declare external authentication functions */ 
FUNCTION authenticateMyUser RETURNS LOGICAL  
    (INPUT cUserID AS CHARACTER, INPUT cPassword AS CHARACTER) IN hAuthProc. 
FUNCTION getAccessCode RETURNS CHARACTER IN hAuthProc. 
/* Build the application trusted domain registry from the database  
   domain registry available for the single database connection */ 
SECURITY-POLICY:LOAD-DOMAINS(1). 
/* Get user ID/password and instantiate external authentication object, 
   which also provides the authentication domain access code */ 
... 
cUserID = ... 
cPassword = ... 
RUN MyAuthentication.p PERSISTENT SET hAuthProc. 
cAccessCode = getAccessCode(). 
/* Create and initialize a client-principal for use with an  
   authentication domain in the application domain registry */ 
CREATE CLIENT-PRINCIPLE hCp. 
hCP:SESSION-ID = "Inventory:" + cUserID + STRING(NOW). 
hCP:USER-ID = cUserID. 
hCP:DOMAIN-NAME = "InventoryApp". 
/* Authenticate and login Progress session ID 
   for the application */ 
If authenticateMyUser(cUserID, cPassword) THEN DO: 
    hCP:SEAL(cAccessCode). 
    /* Assert and validate ID against application domain registry */ 
    IF NOT SECURITY-POLICY:SET-CLIENT(hCP) THEN DO:  
        hCP:LOGOUT(). 
        cRetVal = "User ID not valid Progress session ID". 
    END. 
END. 
ELSE DO: 
    hCP:AUTHENTICATION-FAILED("User not authenticated."). 
    cRetVal = hCP:LOGIN-STATE + ": " + hCP:STATE-DETAIL. 
END. 
/* Handle results of authentication */ 
IF hCP:LOGIN-STATE = "LOGIN" THEN DO: /* Do Inventory stuff... */ 
    ... 
    /* Clear the Progress session ID to end the login session */ 
    hCP:LOGOUT(). 
    DELETE OBJECT hCP. 
END. 
ELSE DO: /* Exit with failure message */ 
    RETURN cRetVal. 
    DELETE OBJECT hCP. 
END. 

In this fragment, the domain access code used by the application is maintained and returned by the same authentication procedure (MyAuthentication.p) that authenticates the user ID. This value, returned using the getAccessCode user-defined function, must match the access code configured for the authentication domain entry in the application’s trusted domain registry.

Also in this code fragment, the setting of the SESSION-ID attribute, which includes the value of STRING(NOW), while valid is not necessarily unique. If you enable auditing for the application, where unique references are more important, use the GENERATE-UUID function to set the SESSION-ID attribute. For more information, see the "Creating and managing unique object identities" section.

Note: If no database connection ID is set for the connected database, the SET-CLIENT( ) method in this fragment also sets the database connection ID, by default, using the database’s own trusted domain registry. If database options are set to trust the application domain registry, SET-CLIENT( ) uses the application domain registry (which in this example has the same content as the database domain registry) to set the database connection ID. Also, if you replace SECURITY:SET-CLIENT(hCP) with SET-DB-CLIENT(hCP) in this code, the entire fragment only sets and manages the database connection ID, and the Progress session ID is blank.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095